package com.example.teacherservice.service;

import com.example.teacherservice.dto.*;
import com.example.teacherservice.entity.*;
import com.example.teacherservice.exception.ResourceNotFoundException;
import com.example.teacherservice.repository.*;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class PracticeService {
    private final PracticeRepository practiceRepository;
    private final CourseRepository courseRepository;
    private final StuPracticeRepository stuPracticeRepository;
    private final StudentRepository studentRepository;
    private final TeacherRepository teacherRepository;

    public List<PracticeDTO> getPracticesByTeacherId(Long teaId) {
        List<Practice> practices = practiceRepository.findByTeaId(teaId);
        return practices.stream().map(this::convertToDTO).collect(Collectors.toList());
    }

    @Transactional
    public Practice createPractice(Long teaId, PracticeCreateDTO dto) {
        Course course = courseRepository.findById(dto.getCouId())
                .orElseThrow(() -> new ResourceNotFoundException("关联课程不存在"));

        Practice practice = new Practice();
        practice.setTeaId(teaId);
        practice.setCourse(course);
        practice.setPraName(dto.getPraName());
        practice.setPraSite(dto.getPraSite());
        practice.setPraMain(dto.getPraMain());
        practice.setDescription(dto.getDescription());
        practice.setLocation(dto.getLocation());
        practice.setStartTime(Timestamp.valueOf(dto.getStartTime()));

        if (dto.getEndTime() != null) {
            practice.setEndTime(Timestamp.valueOf(dto.getEndTime()));
        }

        return practiceRepository.save(practice);
    }

    public PracticeDTO getPracticeDetail(Long id) {
        Practice practice = practiceRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("实践活动不存在"));

        PracticeDTO dto = convertToDTO(practice);
        dto.setStudentCount(practice.getStudentPractices().size());
        dto.setCourseName(practice.getCourse().getCourseName());

        return dto;
    }

    @Transactional
    public Practice updatePractice(Long id, PracticeUpdateDTO dto) {
        Practice practice = practiceRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("实践活动不存在"));

        practice.setPraName(dto.getPraName());
        practice.setPraSite(dto.getPraSite());
        practice.setPraMain(dto.getPraMain());

        return practiceRepository.save(practice);
    }

    @Transactional
    public void deletePractice(Long id) {
        Practice practice = practiceRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("实践活动不存在"));

        practiceRepository.delete(practice);
    }

    @Transactional
    public void addStudentsToPractice(Long praId, List<Long> studentIds) {
        Practice practice = practiceRepository.findById(praId)
                .orElseThrow(() -> new ResourceNotFoundException("实践活动不存在"));

        List<Student> students = studentRepository.findAllById(studentIds);

        students.forEach(student -> {
            if (practice.getStudentPractices().stream()
                    .noneMatch(sp -> sp.getStudent().getId().equals(student.getId()))) {

                StuPractice sp = new StuPractice();
                sp.setPractice(practice);
                sp.setStudent(student);
                practice.getStudentPractices().add(sp);
            }
        });

        practiceRepository.save(practice);
    }

    @Transactional
    public void removeStudentFromPractice(Long praId, Long studentId) {
        Practice practice = practiceRepository.findById(praId)
                .orElseThrow(() -> new ResourceNotFoundException("实践活动不存在"));

        practice.getStudentPractices().removeIf(sp ->
                sp.getStudent().getId().equals(studentId));

        practiceRepository.save(practice);
    }

    public List<StudentDTO> getStudentsInPractice(Long practiceId) {
        return stuPracticeRepository.findByPracticeIdWithStudents(practiceId)
                .stream()
                .map(sp -> {
                    StudentDTO dto = new StudentDTO();
                    BeanUtils.copyProperties(sp.getStudent(), dto);
                    return dto;
                })
                .collect(Collectors.toList());
    }

    public Map<Long, Boolean> checkStudentsInPractice(Long practiceId, List<Long> studentIds) {
        Set<Long> existingStudentIds = stuPracticeRepository
                .findByPracticeIdAndStudentIdIn(practiceId, studentIds)
                .stream()
                .map(sp -> sp.getStudent().getId())
                .collect(Collectors.toSet());

        return studentIds.stream()
                .collect(Collectors.toMap(
                        studentId -> studentId,
                        existingStudentIds::contains
                ));
    }

    private PracticeDTO convertToDTO(Practice practice) {
        PracticeDTO dto = new PracticeDTO();
        BeanUtils.copyProperties(practice, dto);

        // 设置课程名称
        dto.setCourseName(practice.getCourse().getCourseName());

        // 设置学生人数
        dto.setStudentCount(practice.getStudentPractices().size());

        // 设置时间字段（Timestamp转String）
        if(practice.getStartTime() != null) {
            dto.setStartTime(practice.getStartTime().toLocalDateTime().toString());
        }
        if(practice.getEndTime() != null) {
            dto.setEndTime(practice.getEndTime().toLocalDateTime().toString());
        }

        return dto;
    }

    @Transactional
    public Practice updatePracticeStatus(Long id, Integer status) {
        Practice practice = practiceRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("实践活动不存在"));

        // 验证状态转换是否合法
        if (practice.getStatus() == 2 && status == 1) {
            throw new IllegalStateException("已完成的实践不能重新开始");
        }

        practice.setStatus(status);
        return practiceRepository.save(practice);
    }

    // 使用方法2
    public PracticeDetailDTO getPracticeDetailAlternative(Long id) {
        return practiceRepository.findFullPracticeById(id)
                .map(practice -> {
                    PracticeDetailDTO dto = new PracticeDetailDTO();
                    dto.setId(practice.getId());
                    dto.setName(practice.getPraName());
                    dto.setCourseName(practice.getCourse() != null ?
                            practice.getCourse().getCouName() : null);
                    dto.setLocation(practice.getLocation());
                    dto.setStartTime(practice.getStartTime());
                    dto.setEndTime(practice.getEndTime());
                    dto.setStatus(practice.getStatus());
                    dto.setDescription(practice.getDescription());
                    dto.setPraMain(practice.getPraMain());
                    dto.setPraSite(practice.getPraSite());
                    return dto;
                })
                .orElseThrow(() -> new RuntimeException("实践活动不存在"));
    }
}